package cn.yeziji.forum.basic.netty;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 消息载体
 *
 * @author gzkemays
 * @since 2022/11/07 4:12 PM
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message implements Serializable {
  /** 传输类型 */
  Integer type;
  /** 传输内容 */
  String context;
  /** 要通知的用户昵称列表 */
  @JsonIgnore List<String> targets;
  /**
   * 消息生成的时间和实际发送的时间差
   *
   * <p><a href="#">如: 消息是 2:10 分生成，但是实际发送时间为 2:12 分，那么 noticeTime 此时为 2分钟前</a>
   */
  String noticeTime;
  /** 消息生成的时间 */
  Date time;

  public Message(Integer type) {
    this.type = type;
    this.time = new Date();
  }

  public Message(Integer type, String context) {
    this.type = type;
    this.context = context;
    this.time = new Date();
  }

  public Message json(Object data) {
    this.context = JSONObject.toJSONString(data);
    return this;
  }

  public Message currentDate() {
    this.time = new Date();
    return this;
  }

  public Message target(String... targets) {
    if (this.targets == null) {
      this.targets = new ArrayList<>();
    }
    this.targets.addAll(Arrays.asList(targets));
    return this;
  }

  /**
   * 生成时间
   *
   * <ol>
   *   <li>精准度为秒时：1~59秒前
   *   <li>精准度为分钟时：1~59分钟前
   *   <li>精准度为小时时：1~23小时前
   *   <li>精准度为天数时：1~365天前
   *   <li>精准度为年时：1~无限年
   * </ol>
   *
   * <p>如果 {@link #time} 为空时，一般是数据有异常，此时的处理方式是将时间设置为当前发送的时间而后再将时间更新至缓存，便于下次获取时计算时间差
   *
   * @param sendTime 发送消息时的时间
   * @return 构建实际生成时间与发送时间的时间差
   */
  public Message buildNoticeTime(Date sendTime) {
    Instant generateInstant = this.time.toInstant();
    Instant sendInstant = sendTime.toInstant();
    ZoneId zoneId = ZoneId.systemDefault();
    // 构造 local date
    OffsetDateTime generateDate = generateInstant.atZone(zoneId).toOffsetDateTime();
    OffsetDateTime sendDate = sendInstant.atZone(zoneId).toOffsetDateTime();
    long dateBetween = ChronoUnit.SECONDS.between(generateDate, sendDate);
    String prefix = "秒前";
    if (dateBetween == 0) {
      dateBetween = 1;
    }
    if (dateBetween > 59) {
      dateBetween = ChronoUnit.MINUTES.between(generateDate, sendDate);
      prefix = "分钟前";
      if (dateBetween > 59) {
        dateBetween = ChronoUnit.HOURS.between(generateDate, sendDate);
        prefix = "小时前";
        if (dateBetween > 23) {
          dateBetween = ChronoUnit.DAYS.between(generateDate, sendDate);
          prefix = "天前";
          if (dateBetween > 365) {
            dateBetween = ChronoUnit.YEARS.between(generateDate, sendDate);
            prefix = "年前";
          }
        }
      }
    }

    this.noticeTime = dateBetween + prefix;
    return this;
  }
}
